
package br.ufu.lsi.database.engine;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.util.HashSet;
import java.util.Set;

import twitter4j.IDs;
import twitter4j.JSONObject;
import twitter4j.Logger;
import br.ufu.lsi.database.model.Follow;
import br.ufu.lsi.database.model.User;
import br.ufu.lsi.util.FileUtil;
import br.ufu.lsi.util.JSONUtil;
import br.ufu.lsi.util.PropertiesUtil;

/**
 * @author fabiola
 */
public class Updater {

    private static final String ROOT_DIR = PropertiesUtil.getProperty( "ROOT_DIR" );

    private static final String FOLLOWERS_DIR = PropertiesUtil.getProperty( "FOLLOWERS_DIR" );

    private static final String FRIENDS_DIR = PropertiesUtil.getProperty( "FRIENDS_DIR" );

    private static final Logger log = Logger.getLogger( Collector.class );

    private TwitterAccess twitterAccess;

    public Updater( TwitterAccess twitterAccess ) {
        this.twitterAccess = twitterAccess;
    }

    public void start() throws Exception {

        for ( int level = 0; level < 3; level++ ) {

            log.info( "[Level] " + level );

            if ( level == 0 ) {

                scanDirectory( ROOT_DIR, level );

            } else {

                // get followers
                scanDirectory( FOLLOWERS_DIR, level );

                // get friends
                scanDirectory( FRIENDS_DIR, level );
            }
        }
    }

    public void scanDirectory( String directoryPath, int level ) throws Exception {

        File[] listOfFiles = FileUtil.getListOfFiles( directoryPath, level );
        if ( listOfFiles != null ) {
            for ( File file : listOfFiles ) {

                String fileName = file.getAbsolutePath();
                String tempFileName = fileName + ".tmp";

                if ( ! fileName.startsWith( "." ) ) {

                    BufferedReader reader = FileUtil.openInputFile( file );
                    BufferedWriter writer = FileUtil.openOutputFile( tempFileName );

                    String line;
                    while ( ( line = reader.readLine() ) != null ) {

                        // do logic of comparison
                        JSONObject jo = updateRelations( line );
                        jo.write( writer );
                    }
                    writer.close();
                    reader.close();
                    FileUtil.restoreFile( fileName, tempFileName );
                }
            }
        }
    }

    public JSONObject updateRelations( String line ) throws Exception {

        User user = JSONUtil.convertToUser( line );

        // followers
        Set< Follow > followers = user.getFollowers();

        Set< Long > currentFollowersIds = followersList( user.getId() );

        for ( Follow follow : followers ) {

            // starting follower relationship

            // restart follower relationship
            if ( follow.getEnd() != 0 ) {

                if ( currentFollowersIds.contains( follow.getFollower().getId() ) ) {
                    log.info( "Restarting follow relation: [from " + follow.getFollower().getId()
                            + " to " + follow.getFollowee().getId() + "," + user.getScreenName()
                            + "]" );
                }
            }
            
            // ending follower relationship
            if( follow.getEnd() == 0 ) {

                if ( ! currentFollowersIds.contains( follow.getFollower().getId() ) ) {

                    log.info( "Ending follow relation: [from " + follow.getFollower().getId()
                            + " to " + follow.getFollowee().getId() + "," + user.getScreenName()
                            + "]" );

                    follow.setEnd( System.currentTimeMillis() );
                }

            }
        }

        // friends
        Set< Follow > friends = user.getFriends();
        Set< Long > currentFriendsIds = friendsList( user.getId() );

        for ( Follow follow : friends ) {

            // starting friend relationship

            // restart friend relationship
            if ( follow.getEnd() != 0 ) {

                if ( currentFriendsIds.contains( follow.getFollower().getId() ) ) {
                    log.info( "Restarting follow relation: [from " + follow.getFollower().getId()
                            + "," + user.getScreenName() + " to " + follow.getFollowee().getId()
                            + "]" );
                }
            }

            // ending friend relationship
            if ( ! currentFriendsIds.contains( follow.getFollowee().getId() ) ) {

                log.info( "Ending follow relation: [from " + follow.getFollower().getId() + " to "
                        + follow.getFollowee().getId() + "]" );

                follow.setEnd( System.currentTimeMillis() );
            }
        }

        JSONObject jo = JSONUtil.convertToJSON( user );
        return jo;
    }

    /**
     * @param userId
     * @return
     * @throws Exception
     */
    public Set< Long > followersList( long userId ) throws Exception {

        log.info( "getting followers from [" + userId + "]" );

        Set< Long > ids = new HashSet< Long >();

        IDs followers;
        long cursor = - 1;

        do {
            followers = twitterAccess.getFollowersIDs( userId, cursor );

            if ( followers == null ) {
                break;
            }

            log.info( "got " + followers.getIDs().length + " followers..." );

            for ( long id : followers.getIDs() ) {
                ids.add( id );
            }

        } while ( ( cursor = followers.getNextCursor() ) != 0 );

        return ids;

    }

    /**
     * @param userId
     * @return
     * @throws Exception
     */
    public Set< Long > friendsList( long userId ) throws Exception {

        Set< Long > ids = new HashSet< Long >();

        IDs friends;
        long cursor = - 1;

        do {
            friends = twitterAccess.getFriendsIDs( userId, cursor );

            if ( friends == null ) {
                break;
            }

            log.info( "got " + friends.getIDs().length + " friends..." );

            for ( long id : friends.getIDs() ) {
                ids.add( id );
            }

        } while ( ( cursor = friends.getNextCursor() ) != 0 );

        return ids;

    }

    public static void main( String... args ) throws Exception {

        Updater updater = new Updater( new TwitterAccess() );
        updater.start();
    }

}
